Function.RegisterNamespace("Test.System.Event");

[Fixture]
Test.System.Event.EventManager=function(){
    [Fixture]
    function ctor(){
        [Fact]
        function ThrowsIfNoTypesAreRegistered(){
            var expected="System.EventManager.ctor: at least one type must be registered.";

            var actual=Record.Exception(function(){
                new System.Event.EventManager();
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfTypeIsUndefined(){
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                new System.Event.EventManager(undefined);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTypeIsNull(){
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                new System.Event.EventManager(null);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfTypeIsNotConvertibleToString(){
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                new System.Event.EventManager({toString:null});
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function CallsToStringMethodOfType(){
            var target={toString:function(){
                actual=true;
                return "";
            }}
            var actual=false;

            new System.Event.EventManager(target);
            
            Assert.True(actual);
        }

        [Fact]
        function CallsToLowerCaseMethodOfType(){
            var target={toString:function(){
                return {toLowerCase:function(){
                    actual=true;
                    return "";
                }};
            }}
            var actual=false;

            new System.Event.EventManager(target);
            
            Assert.True(actual);
        }
        
        [Fact]
        function RegistersTypeOnEventManager(){
            var targetExpected="expected";

            var target=new System.Event.EventManager(targetExpected);
            var actual=target.Get(targetExpected);
            
            Assert.NotNull(actual);
        }
    }
    
    [Fixture]
    function Add(){
        [Fact]
        function ThrowsIfTypeIsOmitted(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Add();
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTypeIsUndefined(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Add(undefined);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTypeIsNull(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Add(null);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfTypeIsNotConvertibleToString(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Add({toString:null});
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function CallsToStringMethodOfType(){
            var targetExpected="expected";
            var target={toString:function(){
                actual=true;
                return targetExpected;
            }}
            var actual=false;

            new System.Event.EventManager(targetExpected).Add(target,function(){});
            
            Assert.True(actual);
        }

        [Fact]
        function CallsToLowerCaseMethodOfType(){
            var targetExpected="expected";
            var target={toString:function(){
                return {toLowerCase:function(){
                    actual=true;
                    return targetExpected;
                }};
            }}
            var actual=false;

            new System.Event.EventManager(targetExpected).Add(target,function(){});
            
            Assert.True(actual);
        }

        [Fact]
        function ThrowsIfTypeIsNotRegistered(){
            var targetExpected="expected";
            var expected=String.Format("System.EventManager.Add: the event type '{0}' is not registered.",targetExpected);
        
            var actual=Record.Exception(function(){
                new System.Event.EventManager("actual").Add(targetExpected);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfHandlerIsOmitted(){
            var targetExpected="expected";
            var expected="System.EventManager.Add: 'handler' must be a valid Function pointer.";
        
            var actual=Record.Exception(function(){
                new System.Event.EventManager(targetExpected).Add(targetExpected);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfHandlerIsUndefined(){
            var targetExpected="expected";
            var expected="System.EventManager.Add: 'handler' must be a valid Function pointer.";
        
            var actual=Record.Exception(function(){
                new System.Event.EventManager(targetExpected).Add(targetExpected,undefined);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfHandlerIsNull(){
            var targetExpected="expected";
            var expected="System.EventManager.Add: 'handler' must be a valid Function pointer.";
        
            var actual=Record.Exception(function(){
                new System.Event.EventManager(targetExpected).Add(targetExpected,null);
            });
            
            Assert.Equal(expected,actual);
        }
        
        
        [Fact]
        function ThrowsIfHandlerIsNotAValidFunction(){
            var targetExpected="expected";
            var expected="System.EventManager.Add: 'handler' must be a valid Function pointer.";
        
            var actual=Record.Exception(function(){
                new System.Event.EventManager(targetExpected).Add(targetExpected,new Object());
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function AddsEventHandlerForRegisteredType(){
            var targetExpected="expected";
            var expected=function(){};
            var target=new System.Event.EventManager(targetExpected);
            
            target.Add(targetExpected,expected);
            var actual=target.Get(targetExpected)[0];
            
            Assert.Same(expected,actual);
        }
    }
    
    [Fixture]
    function Fire(){
        [Fact]
        function ThrowsIfTypeIsOmitted(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Fire();
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTypeIsUndefined(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Fire(undefined);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTypeIsNull(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Fire(null);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfTypeIsNotConvertibleToString(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Fire({toString:null});
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function CallsToStringMethodOfType(){
            var targetExpected="expected";
            var target={toString:function(){
                actual=true;
                return targetExpected;
            }}
            var actual=false;

            new System.Event.EventManager(targetExpected).Fire(target);
            
            Assert.True(actual);
        }

        [Fact]
        function CallsToLowerCaseMethodOfType(){
            var targetExpected="expected";
            var target={toString:function(){
                return {toLowerCase:function(){
                    actual=true;
                    return targetExpected;
                }};
            }}
            var actual=false;

            new System.Event.EventManager(targetExpected).Fire(target);
            
            Assert.True(actual);
        }

        [Fact]
        function ThrowsIfTypeIsNotRegistered(){
            var targetExpected="expected";
            var expected=String.Format("System.EventManager.Fire: the event type '{0}' is not registered.",targetExpected);
        
            var actual=Record.Exception(function(){
                new System.Event.EventManager("actual").Fire(targetExpected);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function CallsRegisteredEventHandler(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            target.Add(targetExpected,function(context){
                actual=true;
            });
            var actual=false;
            
            target.Fire(targetExpected);
            
            Assert.True(actual);
        }

        [Fact]
        function CallsAllRegisteredEventHandlers(){
            var expected=2;
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            target.Add(targetExpected,function(context){
                actual++;
            });
            target.Add(targetExpected,function(context){
                actual++;
            });
            var actual=0;
            
            target.Fire(targetExpected);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function UsesContextIfProvided(){
            var expected={};
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            target.Add(targetExpected,function(context){
                actual=context;
            });
            var actual=null;
            
            target.Fire(targetExpected,expected);
            
            Assert.Same(expected,actual);
        }

        [Fact]
        function SetsCancelOnContextProvided(){
            var expected={};
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            
            target.Fire(targetExpected,expected);
            var actual=expected.Cancel;
            
            Assert.NotUndefined(actual);
        }

        [Fact]
        function CreatesContextIfNotProvided(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            target.Add(targetExpected,function(context){
                actual=context;
            });
            var actual=null;
            
            target.Fire(targetExpected);
            
            Assert.NotNull(actual);
        }
        
        [Fact]
        function SetsCancelOnContextIfNotProvided(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            target.Add(targetExpected,function(context){
                actual=context.Cancel;
            });
            var actual=undefined;
            
            target.Fire(targetExpected);
            
            Assert.NotUndefined(actual);
        }
    }

    [Fixture]
    function Get(){
        [Fact]
        function ThrowsIfTypeIsOmitted(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Get();
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTypeIsUndefined(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Get(undefined);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTypeIsNull(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Get(null);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfTypeIsNotConvertibleToString(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Get({toString:null});
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function CallsToStringMethodOfType(){
            var targetExpected="expected";
            var target={toString:function(){
                actual=true;
                return targetExpected;
            }}
            var actual=false;

            new System.Event.EventManager(targetExpected).Get(target,function(){});
            
            Assert.True(actual);
        }

        [Fact]
        function CallsToLowerCaseMethodOfType(){
            var targetExpected="expected";
            var target={toString:function(){
                return {toLowerCase:function(){
                    actual=true;
                    return targetExpected;
                }};
            }}
            var actual=false;

            new System.Event.EventManager(targetExpected).Get(target,function(){});
            
            Assert.True(actual);
        }

        [Fact]
        function ThrowsIfTypeIsNotRegistered(){
            var targetExpected="expected";
            var expected=String.Format("System.EventManager.Get: the event type '{0}' is not registered.",targetExpected);
        
            var actual=Record.Exception(function(){
                new System.Event.EventManager("actual").Get(targetExpected);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ReturnsArrayIfTypeIsRegistered(){
            var targetExpected="expected";
        
            var actual=new System.Event.EventManager(targetExpected).Get(targetExpected);
            
            Assert.True(Object.IsType(Array,actual));
        }
        
        [Fact]
        function ReturnsRegisteredHandler(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected=function(){};
        
            target.Add(targetExpected,expected);
            var actual=target.Get(targetExpected)[0];
            
            Assert.Same(expected,actual);
        }
    }
    
    [Fixture]
    function Remove(){
       [Fact]
        function ThrowsIfTypeIsOmitted(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Remove();
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTypeIsUndefined(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Remove(undefined);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTypeIsNull(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Remove(null);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfTypeIsNotConvertibleToString(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var expected="System.EventManager.normalizeType: 'type' must be convertible to String.";        

            var actual=Record.Exception(function(){
                target.Remove({toString:null});
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function CallsToStringMethodOfType(){
            var targetExpected="expected";
            var target={toString:function(){
                actual=true;
                return targetExpected;
            }}
            var actual=false;

            new System.Event.EventManager(targetExpected).Remove(target,function(){});
            
            Assert.True(actual);
        }

        [Fact]
        function CallsToLowerCaseMethodOfType(){
            var targetExpected="expected";
            var target={toString:function(){
                return {toLowerCase:function(){
                    actual=true;
                    return targetExpected;
                }};
            }}
            var actual=false;

            new System.Event.EventManager(targetExpected).Remove(target,function(){});
            
            Assert.True(actual);
        }

        [Fact]
        function ThrowsIfTypeIsNotRegistered(){
            var targetExpected="expected";
            var expected=String.Format("System.EventManager.Remove: the event type '{0}' is not registered.",targetExpected);
        
            var actual=Record.Exception(function(){
                new System.Event.EventManager("actual").Remove(targetExpected);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function RemovesAllHandlersIfHandlerNotSpecified(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            target.Add(targetExpected,function(){});
            target.Add(targetExpected,function(){});

            target.Remove(targetExpected);
            var actual=target.Get(targetExpected);
            
            Assert.True(actual.length==0);
        }

        [Fact]
        function RemovesOnlyMatchingHandlers(){
            var targetExpected="expected";
            var target=new System.Event.EventManager(targetExpected);
            var targetHandler=function(){};
            target.Add(targetExpected,targetHandler);
            target.Add(targetExpected,function(){});

            target.Remove(targetExpected,targetHandler);
            var actual=target.Get(targetExpected);
            
            Assert.True(actual.length==1);
        }

    }
}